// Top-level session spec and output protos for the adaptive load controller.

syntax = "proto3";

package nighthawk.adaptive_load;

import "api/adaptive_load/benchmark_result.proto";
import "api/adaptive_load/metric_spec.proto";
import "api/client/options.proto";
import "envoy/config/core/v3/extension.proto";
import "google/protobuf/duration.proto";
import "google/rpc/status.proto";
import "validate/validate.proto";

// Parameters describing the adjusting and testing stages of an adaptive load
// session, which consists of a series of Nighthawk benchmarks probing for
// the optimal load on the system, followed by a longer benchmark to validate
// the values. Load adjustments are calculated by the selected StepController
// plugin. Metrics can come from Nighthawk stats and counters or
// platform-specific data sources via MetricsPlugins.
message AdaptiveLoadSessionSpec {
  // Settings for MetricsPlugins that obtain metrics from outside sources.
  // An entry is required for every plugin referred to by metric_thresholds,
  // other than the "nighthawk.builtin" plugin. Optional.
  repeated envoy.config.core.v3.TypedExtensionConfig metrics_plugin_configs = 1;
  // Metrics and thresholds that determine load adjustments. The order of
  // metrics is not significant. Required.
  repeated MetricSpecWithThreshold metric_thresholds = 2 [(validate.rules).repeated .min_items = 1];
  // Metrics that are collected and included in the output but not taken into
  // account when adjusting the load. May be used for debugging or
  // visualization. Optional.
  repeated MetricSpec informational_metric_specs = 3;
  // A proto describing Nighthawk Service traffic. See
  // https://github.com/envoyproxy/nighthawk/blob/main/api/client/options.proto
  //
  // The adaptive load controller will return an error if the |duration| field is set within
  // |nighthawk_traffic_template|.
  //
  // If |open_loop| is unset, it will be overridden to true by the adaptive load controller. This is
  // to support the typical case where the controller needs full control over attempted requests per
  // second, which could conflict with the backpressure mechanism of closed-loop mode. Note that in
  // standalone Nighthawk clients, closed-loop mode is the default.
  //
  // The controller will override at least one field in this proto to vary the load, such as the
  // requests_per_second field or headers. Any existing value for such a field in the template will
  // be ignored.
  //
  // All other fields in |nighthawk_traffic_template| are passed through to the
  // Nighthawk Service.
  //
  // Note that |concurrency| in |nighthawk_traffic_template| multiplies the total
  // RPS sent.
  //
  // Required.
  nighthawk.client.CommandLineOptions nighthawk_traffic_template = 4
      [(validate.rules).message.required = true];
  // The duration of each short benchmark during the adjusting stage. Optional, default 10 seconds.
  google.protobuf.Duration measuring_period = 5
      [(validate.rules).duration = {gt {seconds: 0 nanos: 0}}];
  //  Maximum amount of time the adjusting stage should wait for convergence
  //  before returning an error. Optional, default 300 seconds.
  google.protobuf.Duration convergence_deadline = 6
      [(validate.rules).duration = {gt {seconds: 0 nanos: 0}}];
  // The duration of the single benchmark session of the testing stage to
  // confirm the performance at the level of load found in the adjusting stage.
  // Optional, default 30 seconds.
  google.protobuf.Duration testing_stage_duration = 7
      [(validate.rules).duration = {gt {seconds: 0 nanos: 0}}];
  // The duration to wait between individual short benchmarks during the
  // adjusting stage and between the last short benchmark of the adjusting stage
  // and the testing stage.
  // Optional, defaults to zero duration.
  google.protobuf.Duration benchmark_cooldown_duration = 9
      [(validate.rules).duration = {gt {seconds: 0 nanos: 0}}];
  // Selects and configures a StepController plugin. Required.
  envoy.config.core.v3.TypedExtensionConfig step_controller_config = 8
      [(validate.rules).message.required = true];
}

// Complete description of an adaptive load session, including metric scores
// for every degree of load attempted during the adjusting stage.
message AdaptiveLoadSessionOutput {
  // Results of each short benchmark performed during the adjusting stage.
  repeated BenchmarkResult adjusting_stage_results = 2;
  // Result of the single benchmark of the testing stage.
  BenchmarkResult testing_stage_result = 3;
  // Metrics and thresholds that were used to determine load adjustments, as referenced in the
  // BenchmarkResults.
  repeated MetricSpecWithThreshold metric_thresholds = 4;
}
